#include <Ogre.h>
#include <OIS/OIS.h>
using namespace Ogre;

#include "MarbleMax.h"

bool Marble_Max::createInputListener(Ogre::RenderWindow *renderWindow)
{
	OIS::ParamList paramList; // creation parameters
	size_t windowHnd = 0; // window handle
	std::ostringstream windowHndStr; // window string

	// Get window handle
	renderWindow->getCustomAttribute( "WINDOW", &windowHnd );

	// Fill parameter list
	windowHndStr << (unsigned int) windowHnd;
	paramList.insert( std::make_pair( std::string( "WINDOW" ), windowHndStr.str() ) );

	// Create inputsystem
	mInputMgr = OIS::InputManager::createInputSystem( paramList );

	// If possible create a buffered keyboard
	mKeyboard = static_cast<OIS::Keyboard*>( mInputMgr->createInputObject( OIS::OISKeyboard, true ) );
	mKeyboard->setEventCallback( this );

	// If possible create a buffered mouse
	mMouse = static_cast<OIS::Mouse*>( mInputMgr->createInputObject( OIS::OISMouse, true ) );
	mMouse->setEventCallback( this );

	// Get window size
	unsigned int width, height, depth;
	int left, top;
	renderWindow->getMetrics( width, height, depth, left, top );
	const OIS::MouseState& ms = mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
	return true;
}
void Marble_Max::killInputListener()
{
	if(mInputMgr)
	{
		if(mMouse)
			mInputMgr->destroyInputObject(mMouse); // kill mouse
		if(mKeyboard)
			mInputMgr->destroyInputObject(mKeyboard); // kill keyboard
		if(mInputMgr)
			mInputMgr->destroyInputSystem(mInputMgr); // kill manager
		OIS::InputManager::destroyInputSystem(mInputMgr);
		mInputMgr = 0;
	}
}

bool Marble_Max::keyPressed(const OIS::KeyEvent& kevt)
{
	using namespace OIS;
	switch(currGameState)
	{
	case ROLLSTATE:
		switch(kevt.key)
		{
		case KC_ESCAPE:
			mDebugOverlay->hide();
			currGameState = MENUSTATE;
			break;
		case KC_A:
			mMoveVector.x -= 8;
			break;
		case KC_D:
			mMoveVector.x += 8;
			break;
		case KC_E:
			mMoveVector.y += 8;
			break;
		case KC_Q:
			mMoveVector.y -= 8;
			break;
		case KC_W:
			mMoveVector.z -= 10;
			break;
		case KC_S:
			mMoveVector.z += 10;
			break;
		}
	case MENUSTATE:
		switch(kevt.key)
		{
		case KC_ESCAPE:
			mWindow->destroy();
			break;
		case KC_P:
			currGameState = BUILDSTATE;
			createMarbleScene();
			break;
		}
		break;
	case BUILDSTATE:
		switch(kevt.key)
		{
		case KC_ESCAPE:
			mDebugOverlay->hide();
			currGameState = MENUSTATE;
			break;
		case KC_A:
			mMoveVector.x -= 8;
			break;
		case KC_D:
			mMoveVector.x += 8;
			break;
		case KC_E:
			mMoveVector.y += 8;
			break;
		case KC_Q:
			mMoveVector.y -= 8;
			break;
		case KC_W:
			mMoveVector.z -= 10;
			break;
		case KC_S:
			mMoveVector.z += 10;
			break;
		}
		break;
	}
	return true;
}
bool Marble_Max::keyReleased(const OIS::KeyEvent &kevt)
{
	using namespace OIS;
	switch(currGameState)
	{
	case ROLLSTATE:
		switch(kevt.key)
		{
		case KC_A:
			mMoveVector.x += 8;
			break;
		case KC_D:
			mMoveVector.x -= 8;
			break;
		case KC_E:
			mMoveVector.y -= 8;
			break;
		case KC_Q:
			mMoveVector.y += 8;
			break;
		case KC_W:
			mMoveVector.z += 10;
			break;
		case KC_S:
			mMoveVector.z -= 10;
			break;
		}
		break;
	case MENUSTATE:
		break;
	case BUILDSTATE:
		switch(kevt.key)
		{
		case KC_A:
			mMoveVector.x += 8;
			break;
		case KC_D:
			mMoveVector.x -= 8;
			break;
		case KC_E:
			mMoveVector.y -= 8;
			break;
		case KC_Q:
			mMoveVector.y += 8;
			break;
		case KC_W:
			mMoveVector.z += 10;
			break;
		case KC_S:
			mMoveVector.z -= 10;
			break;
		case KC_B:
			switch(currBuildMode)
			{
			case BM_BUILD:
				currBuildMode = BM_BULLDOZE;
				mouseNode->setVisible(false);
				mouseNode->showBoundingBox(false);
				mouseNode = mSceneMgr->getSceneNode("BULLDOZENODE");
				mouseNode->showBoundingBox(true);
				break;
			case BM_BULLDOZE:
				currBuildMode = BM_BUILD;
				if(mouseNode->getName().substr(0,8) == "MMObject")
				{
					mSceneMgr->getEntity(mouseNode->getAttachedObject(0)->getName())->setMaterialName("SetCube");
					mouseNode->showBoundingBox(false);
				}
				else
				{
					mouseNode->setVisible(false);
					mouseNode->showBoundingBox(false);
				}
				mouseNode = mSceneMgr->getSceneNode("NORMALNODE");
				mouseNode->setVisible(true);
				mouseNode->showBoundingBox(true);
				break;
			}
			break;
		case KC_RETURN:
			currGameState = ROLLSTATE;
			CEGUI::MouseCursor::getSingleton().hide();
			mouseNode->showBoundingBox(false);
			startRoll();
			break;
		case KC_SPACE:
			if(currBuildMode == BM_BUILD)
			{
				switch(mCurrTrack)
				{
				case NORMAL:
					mCurrTrack = HALF;
					mouseNode->setVisible(false);
					mouseNode->showBoundingBox(false);
					mouseNode = mSceneMgr->getSceneNode("HALFNODE");
					mouseNode->showBoundingBox(true);
					mouseNode->setVisible(true);
					mDebugString = "half";
					objectHeight = 0;
					break;
				case HALF:
					mCurrTrack = DOUBLE;
					mouseNode->setVisible(false);
					mouseNode->showBoundingBox(false);
					mouseNode = mSceneMgr->getSceneNode("DOUBLENODE");
					mouseNode->showBoundingBox(true);
					mouseNode->setVisible(true);
					mDebugString = "double";
					objectHeight = 0;
					break;
				case DOUBLE:
					mCurrTrack = SINGLE;
					mouseNode->setVisible(false);
					mouseNode->showBoundingBox(false);
					mouseNode = mSceneMgr->getSceneNode("SINGLENODE");
					mouseNode->showBoundingBox(true);
					mouseNode->setVisible(true);
					mDebugString = "single";
					objectHeight = 0;
					break;
				case SINGLE:
					mCurrTrack = SHARP;
					mouseNode->setVisible(false);
					mouseNode->showBoundingBox(false);
					mouseNode = mSceneMgr->getSceneNode("SHARPNODE");
					mouseNode->showBoundingBox(true);
					mouseNode->setVisible(true);
					mDebugString = "sharp";
					objectHeight = 0;
					break;
				case SHARP:
					mCurrTrack = NORMAL;
					mouseNode->setVisible(false);
					mouseNode->showBoundingBox(false);
					mouseNode = mSceneMgr->getSceneNode("NORMALNODE");
					mouseNode->showBoundingBox(true);
					mouseNode->setVisible(true);
					mDebugString = "normal";
					objectHeight = 0;
					break;
				}
			}
			break;
		case KC_RIGHT:
			mouseNode->rotate(Quaternion(Radian(Math::PI / 2),Vector3(0,1,0)),Node::TS_WORLD);
			break;
		case KC_LEFT:
			mouseNode->rotate(Quaternion(Radian(-(Math::PI / 2)),Vector3(0,1,0)),Node::TS_WORLD);
			break;
		case KC_UP:
			increaseSlope();
			break;
		case KC_DOWN:
			decreaseSlope();
			break;
		}
		break;
	}
	return true;
}
bool Marble_Max::mousePressed(const OIS::MouseEvent& mevt, OIS::MouseButtonID button)
{
	using namespace OIS;
	switch(currGameState)
	{
	case ROLLSTATE:
		switch(button)
		{
		case MB_Right:
			mRightMDown = true;
			break;
		case MB_Left:
			mLeftMDown = true;
			break;
		}
		break;
	case MENUSTATE:
		break;
	case BUILDSTATE:
		switch(button)
		{
		case MB_Right:
			mRightMDown = true;
			CEGUI::MouseCursor::getSingleton().hide();
			break;
		case MB_Left:
			mLeftMDown = true;
			break;
		}
		break;
	}
	return true;
}
bool Marble_Max::mouseReleased(const OIS::MouseEvent &mevt, OIS::MouseButtonID button)
{
	using namespace OIS;
	switch(currGameState)
	{
	case ROLLSTATE:
		switch(button)
		{
		case MB_Right:
			mRightMDown = false;
			break;
		case MB_Left:
			mLeftMDown = false;
			mLeftMUp = true;
			break;
		}
		break;
	case MENUSTATE:
		break;
	case BUILDSTATE:
		switch(button)
		{
		case MB_Right:
			mRightMDown = false;
			CEGUI::MouseCursor::getSingleton().show();
			break;
		case MB_Left:
			mLeftMDown = false;
			mLeftMUp = true;
			break;
		}
		break;
	}
	return true;
}
bool Marble_Max::mouseMoved(const OIS::MouseEvent& mevt)
{
	using namespace OIS;
	switch(currGameState)
	{
	case ROLLSTATE:
		mRotX = Ogre::Degree(-mevt.state.X.rel * 0.13);
		mRotY = Ogre::Degree(-mevt.state.Y.rel * 0.13);
		break;
	case MENUSTATE:
		break;
	case BUILDSTATE:
		if(mRightMDown)
		{
			mRotX = Ogre::Degree(-mevt.state.X.rel * 0.13);
			mRotY = Ogre::Degree(-mevt.state.Y.rel * 0.13);
		}
		else if(!mRightMDown)
		{
			mGUISystem->getSingleton().injectMouseMove(mevt.state.X.rel,mevt.state.Y.rel);
		}
		if(mevt.state.Z.abs != 0)
		{
			objectHeight += mevt.state.Z.rel/12;
			if(objectHeight < 0)
				objectHeight = 0;
		}

		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
		Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(mevt.state.width), mousePos.d_y/float(mevt.state.height));
        mRaySceneQuery->setRay(mouseRay);

		break;
	}
	return true;
}